package hit.core;

import static org.junit.Assert.*;

import java.util.Date;
import java.util.Iterator;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class ProductIndexTest {

	ProductIndex productIndex;
	
	@Before
	public void setUp() {
		productIndex = HomeInventoryTracker.GetEmptyInstance().GetProductIndex();
	}

	@After
	public void tearDown() {
		productIndex = null;
	}
	
	public Product GetTestProduct1() {
		Product product = new Product();
		
		product.SetCreation(new Date());
		product.SetBarcode(new Barcode("036725604919"));
		product.SetDescription("Testing");
		product.SetShelfLife(3);
		product.SetSize(new Size(2, Size.Unit.COUNT));
		product.SetThreeMonth(10);
		
		return product;
	}
	
	public Product GetTestProduct2() {
		Product product = new Product();
		
		product.SetCreation(new Date());
		product.SetBarcode(new Barcode("885370395143"));
		product.SetDescription("Testing 2");
		product.SetShelfLife(5);
		product.SetSize(new Size(1.2, Size.Unit.GRAMS));
		product.SetThreeMonth(15);
		
		return product;
	}
	
	@Test
	public void TestAddProductDifferentContainers() {
		
		StorageUnit testUnit1 = new StorageUnit("TestUnit1");
		StorageUnit testUnit2 = new StorageUnit("TestUnit2");
		
		Product testProd1 = GetTestProduct1();
		productIndex.AddProduct(testProd1, testUnit1);
		assertEquals("Did not correctly Add Item", productIndex.GetByBarcode(testProd1.GetBarcode()), testProd1);
		assertEquals("Not correctly added to Container",productIndex.GetByProductContainer(testUnit1).next(), testProd1);
		
		Product testProd2 = GetTestProduct2();
		productIndex.AddProduct(testProd2, testUnit2);
		assertEquals("Did not correctly Add Item", productIndex.GetByBarcode(testProd2.GetBarcode()), testProd2);
		assertEquals("Not correctly added to Container",productIndex.GetByProductContainer(testUnit2).next(), testProd2);
	}
	
	@Test
	public void TestAddProductSameContainer() {
		StorageUnit testUnit1 = new StorageUnit("TestUnit1");
		
		Product testProd1 = GetTestProduct1();
		Product testProd2 = GetTestProduct2();
		productIndex.AddProduct(testProd1, testUnit1);
		productIndex.AddProduct(testProd2, testUnit1);
		
		assertEquals("Did not correctly Add Item", productIndex.GetByBarcode(testProd1.GetBarcode()), testProd1);
		assertEquals("Did not correctly Add Item", productIndex.GetByBarcode(testProd2.GetBarcode()), testProd2);
		
		boolean foundProd1 = false;
		boolean foundProd2 = false;
		
		Iterator<Product> iter = productIndex.GetByProductContainer(testUnit1);
		
		while (iter.hasNext())
		{
			Product temp = iter.next();
			
			if (temp == testProd1)
				foundProd1 = true;
			else if (temp == testProd2)
				foundProd2 = true;
		}
		
		assertTrue("Product 1 not added to container correctly", foundProd1);
		assertTrue("Product 2 not added to container correctly", foundProd2);
	}
	
	@Test
	public void TestCanAddToContainer() {
		
		StorageUnit testUnit1 = new StorageUnit("TestUnit 1");
		ProductGroup testGroup1 = new ProductGroup("TestGroup 1");
		testGroup1.SetParentContainer(testUnit1);
		testGroup1.SetThreeMonth(new Size(12, Size.Unit.COUNT));
		testUnit1.AddProductGroup(testGroup1);
		
		StorageUnit testUnit2 = new StorageUnit("TestUnit 2");
		ProductGroup testGroup2 = new ProductGroup("TestGroup 2");
		testGroup2.SetParentContainer(testUnit2);
		testGroup2.SetThreeMonth(new Size(30, Size.Unit.COUNT));
		testUnit2.AddProductGroup(testGroup2);
		
		Product product = GetTestProduct1();
		productIndex.AddProduct(product, testUnit1);
		
		assertFalse("Should not be able to add to testUnit1", productIndex.CanAddProductToContainer(product, testGroup1));
		assertTrue("Should be able to add to testUnit2", productIndex.CanAddProductToContainer(product, testGroup2));
		
		productIndex.AddProductToContainer(product, testGroup2);
		assertFalse("Should not be able to add to testUnit2", productIndex.CanAddProductToContainer(product, testUnit2));
	}
	
	@Test
	public void TestUpdateAndRemove() {
		StorageUnit testUnit = new StorageUnit("ChocolateMilk");
		Product product = GetTestProduct1();
		
		productIndex.AddProduct(product, testUnit);
		
		Product newProd = GetTestProduct2();
		
		productIndex.EditProduct(product, newProd);
		
		assertEquals("Barcode did not match after update.", product.GetBarcode(), newProd.GetBarcode());
		assertEquals("Creation date did not match after update.", product.GetCreation(), newProd.GetCreation());
		assertEquals("Description did not match after update.", product.GetDescription(), newProd.GetDescription());
		assertEquals("Shelf Life did not match after update.", product.GetShelfLife(), newProd.GetShelfLife());
		assertEquals("Size did not match after update.", product.GetSize(), newProd.GetSize());
		assertEquals("Could not find under new Barcode.", product, productIndex.GetByBarcode(newProd.GetBarcode()));
		
		//assertEquals("Found product that should have been removed.", product, productIndex.GetByBarcode(newProd.GetBarcode()));
	}
	
	@Test
	public void TestRemoveProduct() {
		StorageUnit testUnit = new StorageUnit("ChocolateMilk");
		Product product = GetTestProduct1();
		
		productIndex.AddProduct(product, testUnit);
		productIndex.RemoveProduct(product);
		assertNull(productIndex.GetByBarcode(product.GetBarcode()));
	}
	
	
	@Test(expected=IllegalArgumentException.class)
	public void TestAddInvalidProduct() {
		StorageUnit testUnit = new StorageUnit("Hi Mom!");
		productIndex.AddProduct(new Product(), testUnit);
	}
	
	@Test
	public void TestFindProductContainer() {
		Product product1 = GetTestProduct1();
		Product product2 = GetTestProduct2();
		
		ProductGroup group = new ProductGroup("Laxatives");
		StorageUnit unit = new StorageUnit("Unlocked Medicine Cabinet");
		group.SetParentContainer(unit);
		
		product1.AddProductContainer(group);
		product2.AddProductContainer(unit);
		
		assertEquals(productIndex.FindProductContainer(group, product1), group);
		assertEquals(productIndex.FindProductContainer(unit, product1), group);
		assertNull(productIndex.FindProductContainer(group, product2));
		
		assertEquals(productIndex.FindProductContainer(unit, product2), unit);
	}
}
